#![allow(dead_code)]

struct BoxLrn {}

impl BoxLrn {
    pub fn hello() {
        println!("Box learning!");
    }
}

#[cfg(test)]
mod tests {
    use std::vec;

    use stdext::function_name;

    #[test]
    fn basic_box_test() {
        let x = Box::new(5);
        let mut hashmap = std::collections::HashMap::new();
        hashmap.insert(1, 15);
        println!("x = {}", x);
        println!("hashmap = {:?}", hashmap);
        assert_eq!(5, *x);

        fn foo(x: Box<i32>) {
            println!("x = {}", x);
        }
    }

    #[test]
    fn macro_function_name() {
        print_name();
        fn print_name() {
            // 通过宏确认结尾是否为test, false
            println!("{}", function_name!().ends_with("test"));
            println!("function name: {}", function_name!());
        }
    }

    #[test]
    fn ref_box() {
        {
            let x = 5;
            let y = &x;
            // 再堆上分配内存，将x的值复制到堆上。i32 实现了copy traits，因此改变z不会影响x的值
            let mut z = Box::new(x);
            assert_eq!(5, x);
            assert_eq!(5, *y);
            assert_eq!(5, *z);
            *z = 10;
            assert_eq!(10, *z);
            assert_eq!(5, x);

            // 通过move关键字，将z的所有权转移给super_z
            let mut super_z = z;
            *super_z = 20;
            assert_eq!(20, *super_z);
        }
        {
            // 通过&mut改变x的值
            let mut x = 10;
            // z是x的可变引用
            let z = &mut x;
            *z = 20;
            assert_eq!(*z, 20);
            assert_eq!(x, 20);
            // println!("inside z = {}", z.clone());
            println!("inside x = {}", x);
        }
        {
            // 存在堆上的类型，没有实现copy trait，因此会发生move
            let arr = vec![1, 2, 3];
            let mut arr_box = Box::new(arr); // arr_box获得了可变指针，因此取得了arr的所有权
            (*arr_box)[0] = 10;
            assert_eq!(*arr_box, vec![10, 2, 3]);
            // assert_eq!(arr, vec![1, 2, 3]);
        }
        {
            #[derive(Debug)]
            struct Person {
                name: String,
                age: u8,
            }

            let p1 = Person {
                name: String::from("xiaoming"),
                age: 18,
            };

            let p2 = Box::new(p1); // p1被move了

            // 获得p2的指针是安全行为，改变是不安全的
            let pt1 = &*p2 as *const Person as *mut Person;
            unsafe {
                pt1.write(Person {
                    name: String::from("daming"),
                    age: 34,
                });
            };

            println!("p2 = {:?}", p2);
        }
    }

    #[test]
    #[allow(unused_assignments)]
    fn pointer_ref() {
        {
            // NOTE: mut x: &mut i32 前一个mut表示x是可变的，后一个mut表示x指向的值是可变的
            println!("|mut x:&mut i32|");
            let mut x = 10;
            let mut y = 20;
            let mut mut_x = &mut x;
            x = 123;
            mut_x = &mut y;
            dbg!(mut_x); // mut_x = 20
            dbg!(x); // x = 123
        }
        {
            // NOTE: x: &mut i32 x是不可变的，后一个mut表示x指向的值是可变的
            println!("|    x:&mut i32|");
            let mut x = 10;
            let mut_x = &mut x;
            *mut_x = 20;
            dbg!(mut_x); // mut_x = 20
            dbg!(x); // x = 20
        }
        {
            // NOTE: mut x: &i32 前一个mut表示x是可变的，后一个mut表示x指向的值是不可变的
            println!("|mut x:&    i32|");
            let x = 10;
            let mut mut_x = &x;
            mut_x = &123;
            dbg!(mut_x); // mut_x = 123
            dbg!(x); // x = 10
        }
    }
}
